package edu.lingnan.aop;


import edu.lingnan.constant.LogTypeEnum;
import edu.lingnan.dto.*;
import edu.lingnan.entity.*;
import edu.lingnan.service.BookingService;
import edu.lingnan.service.ClassRoomService;
import edu.lingnan.service.LogService;
import edu.lingnan.service.SeatService;
import edu.lingnan.util.IpUtils;

import edu.lingnan.vo.LogStudentVo;
import edu.lingnan.vo.Result;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;


import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @ClassName LogAspect
 * @Description 日志注解AOP
 * @Author kang
 * @Date 2022/9/14 下午 4:00
 * @Version 1.0
 */
@Component
@Aspect
@Slf4j
public class LogAspect {

    @Autowired
    private ThreadPoolExecutor executor;

    @Autowired
    private IpUtils ipUtils;

    @Autowired
    private LogService logService;

    @Autowired
    private ClassRoomService classRoomService;

    @Autowired
    private BookingService bookingService;

    @Autowired
    private SeatService seatService;

    @Autowired
    private HttpServletRequest request;


    /**
     * @param
     * @return void
     * @description 定义切点，在注解位置切入代码
     * @author kang
     * @date 2022/9/14 下午 4:05
     */
    @Pointcut("@annotation(edu.lingnan.annotation.Log)")
    public void logPoinCut() {
    }

    /**
     * @param joinPoint JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象.
     * @return void
     * @description 后置通知，指定该增强方法在切入点方法后执行
     * @author kang
     * @date 2022/9/14 下午 4:11
     */
    @Around(value = "logPoinCut()")
    public Object saveSysLog(ProceedingJoinPoint joinPoint) {
        //定义一个日志
        Log log = new Log();
        Result result = null;

        //从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取切入点所在的方法
        Method method = signature.getMethod();
        //获取注解
        edu.lingnan.annotation.Log annotation = method.getAnnotation(edu.lingnan.annotation.Log.class);

        if (annotation != null) {
            try {
                //获取注解属性
                LogTypeEnum module = annotation.module();
                //获得接口请求参数
                Object[] args = joinPoint.getArgs();

                //获取接口的返回值
                result = (Result) joinPoint.proceed();

                HttpSession session = request.getSession();
                LogAspect.log.info("sessionId为：" + session);


                LogStudentVo loginInfo = (LogStudentVo) session.getAttribute("loginInfo");
                System.out.println(loginInfo);

                //根据日志类型
                switch (module) {
                    //登录
                    case Login:
                        loginLog(log, result, args, loginInfo);
                        break;
                    //注册
                    case Register:
                        registerLog(log, result, args);
                        break;
                    // 选座模块
                    case SeatSelection:
                        seatSelectionLog(log, result, args);
                        break;
                    //    请假模块
                    case Leave:
                        leaveLog(log, args);
                        break;
                    //    新增课室
                    case AddClassroom:
                        addClassroomLog(log, args);
                        break;
                    //    删除教室
                    case DeleteClassroom:
                        deleteClassroomLog(log, args);
                        break;
                    //    审核账号
                    case ExamineStudent:
                        examineStudentLog(log, args);
                        break;
                    //    退座位模块
                    case BackSeat:
                        backSeatLog(log, args);
                        break;
                    //    修改密码
                    case UpdatePassword:
                        updatePasswordLog(log, args, result);
                        break;
                    //    重置密码
                    case ResetPassword:
                        ResetPasswordLog(log, args, result);
                        break;
                    case UpdateInfo:
                        updateInfoLog(log, args, result);
                        break;
                    default:
                        break;
                }



                //设置日志时间
                log.setLogTime(LocalDateTime.now())
                        //IP
                        .setLogIp(ipUtils.getIpAddress(request))
                        //模块
                        .setLogModule(module.getModel())
                        //动作信息
                        .setLogAction(result.getMessage());
                if (loginInfo != null) {
                    log
                            //账号
                            .setLogAccount(loginInfo.getSId())
                            //姓名
                            .setLogUsername(loginInfo.getSName());
                }


                LogAspect.log.info("需要插入的日志信息为：{}" + log);
                logService.save(log);

            } catch (Throwable e) {
                throw new RuntimeException(e);
            }
        }
        return result;
    }

    /**
     * 登录日志
     *
     * @param log
     * @param result
     * @param args
     * @param loginInfo
     */
    private void loginLog(Log log, Result result, Object[] args, LogStudentVo loginInfo) {
        try {
            Teacher teacher = (Teacher) args[0];
            log.setLogAccount(teacher.getTNum());
        }catch (Exception e){
            Student student = (Student) args[0];
            log.setLogAccount(student.getSId());
        }
    }

    /**
     * 更新信息
     *
     * @param log
     * @param args
     * @param result
     */
    private void updateInfoLog(Log log, Object[] args, Result result) {
        log.setLogDesc(args[0].toString());
    }

    /**
     * 重置密码
     *
     * @param log
     * @param args
     * @param result
     */
    private void ResetPasswordLog(Log log, Object[] args, Result result) {
        String arg = (String) args[0];
        StringBuilder builder = new StringBuilder();
        String s = builder.append("被修改人学号： ").append(arg).append("---重置密码为123456").toString();
        log.setLogDesc(s);
    }

    /**
     * 修改密码日志
     *
     * @param log
     * @param args
     * @param result
     */
    private void updatePasswordLog(Log log, Object[] args, Result result) {
        StudentPasswordReq arg = (StudentPasswordReq) args[0];
        StringBuilder builder = new StringBuilder();
        String s = builder.append("被修改人学号： ").append(arg.getSId()).toString();
        log.setLogDesc(s);
    }


    /**
     * @param log    需要构建的日志(动作结果描述)
     * @param result 接口返回结果
     * @param args   接口参数
     * @return void
     * @description 构建注册日志
     * @author kang
     * @date 2022/9/15 上午 8:13
     * @throws:
     */
    private void registerLog(Log log, Result result, Object[] args) {
        Student arg = (Student) args[0];
        String sId = arg.getSId();
        String des = sId;
        if (result.getSuccess()) {
            des += " 注册成功";
        } else {
            des += " 注册失败";
        }
        log.setLogDesc(des);
    }

    /**
     * @param log    需要构建的日志(动作结果描述)
     * @param result 接口返回结果
     * @param args   接口参数
     * @return void
     * @description 构建选座模块日志
     * @author kang
     * @date 2022/9/15 上午 9:31
     */
    private void seatSelectionLog(Log log, Result result, Object[] args) {
        StudentReq studentReq = (StudentReq) args[0];
        String des = "";
        if (result.getSuccess()) {
            ClassRoom room = classRoomService.getById(studentReq.getRId());
            des = room.getRBuilding() + " " + room.getRRoom();
        }
        log.setLogDesc(des);
    }

    /**
     * @param log  需要构建的日志(动作结果描述)
     * @param args 接口参数
     * @return void
     * @description 构建退座模块日志
     * @author kang
     * @date 2022/9/15 上午 9:31
     */
    private void backSeatLog(Log log, Object[] args) {
        SeatReturn seatReturn = (SeatReturn) args[0];
        String des = "";
        Integer bId = seatReturn.getBId();
        des = getBookingClassRoomInfo(des, bId);
        log.setLogDesc(des);
    }


    /**
     * @param log  需要构建的日志(动作结果描述)
     * @param args 接口参数
     * @return void
     * @description 请假模块
     * @author kang
     * @date 2022/9/15 下午 4:00
     */
    private void leaveLog(Log log, Object[] args) {
        Record record = (Record) args[0];
        String desc = "";
        desc = getBookingClassRoomInfo(desc, record.getBId());
        desc += "请假至 " + record.getReStartTime() + " 共" + record.getReDays() + "天";
        log.setLogDesc(desc);
    }

    /**
     * 添加教室日志
     *
     * @param log
     * @param args
     */
    private void addClassroomLog(Log log, Object[] args) {
        ClassRoomReq classRoomReq = (ClassRoomReq) args[0];
        String des = classRoomReq.getRBuilding() + classRoomReq.getRRoom() + "共" + classRoomReq.getRNums() + "个位置";
        log.setLogDesc(des);
    }

    /**
     * 删除教室日志
     *
     * @param log
     * @param args
     */
    private void deleteClassroomLog(Log log, Object[] args) {
        Integer id = (Integer) args[0];
        ClassRoom classRoom = classRoomService.getById(id);
        String des = classRoom.getRBuilding() + classRoom.getRRoom();
        log.setLogDesc(des);
    }

    /**
     * 学生注册审核
     *
     * @param log
     * @param args
     */
    private void examineStudentLog(Log log, Object[] args) {
        StudentCheckReq studentCheckReq = (StudentCheckReq) args[0];
        String sId = studentCheckReq.getSId();
        String status = "";
        if ("1".equals(studentCheckReq.getSStatus())) {
            status += "通过申请";
        } else {
            status += "驳回注册";
        }
        log.setLogDesc(sId + status);
    }


    /**
     * 获取预约教室信息
     *
     * @param des 详细
     * @param bId
     * @return
     */
    private String getBookingClassRoomInfo(String des, Integer bId) {
        //获取预约记录
        Booking booking = bookingService.getById(bId);
        //从预约记录中获取座位号
        Integer seatId = booking.getSeatId();
        //查询该座位号对应的座位
        Seat seat = seatService.getById(seatId);
        //查询该座位的房间id
        Integer rId = seat.getRId();
        //通过房间id获取该classroom
        ClassRoom classRoom = classRoomService.getById(rId);
        //教室名称
        String rBuilding = classRoom.getRBuilding();
        //房间号
        String rRoom = classRoom.getRRoom();
        des += rBuilding + " " + rRoom + " " + seat.getSeatNum() + " 号座位";
        return des;
    }


}
